import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:xsdk_flutter/xsdk/operation/x_constant_temp.dart';
import 'package:xsdk_flutter/xsdk/utils/queue/x_bean_queue_message.dart';
import 'package:xsdk_flutter/xsdk/operation/x_mixin_release.dart';
import 'package:xsdk_flutter/xsdk/utils/json/x_utils_json.dart';
import 'package:xsdk_flutter/xsdk/utils/socket/support/x_socket_notify_callback.dart';
import 'package:xsdk_flutter/xsdk/utils/socket/x_utils_socket.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_jiami.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_number.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_string.dart';

//设备连接状态
typedef XFunctionSocketDeviceDisconnectCallback<T> = void Function(String? ip,int? port);
//用于长连接
class XSocketConnectItem with XMixinRelease{

  Socket? socket;

  late String ip;//对方的ip
  late int port;//对方的port

  bool isServer;//是否服务端的socket

  /*
  是否自定义socket通讯
   */
  bool isCustomSocketCommunication=false;

  XFunctionSocketDeviceDisconnectCallback? disconnectCallback;

  XSocketConnectItem(
      {
        required this.isServer,//是否服务端
        required this.isCustomSocketCommunication,
        required this.socket,
        required this.disconnectCallback,
        required bool isReceiveMsg,//接收消息
      }
      ){
    ip=socket!.remoteAddress.address;
    port=socket!.remotePort;

    //状态
    socket?.done.onError((error, stackTrace){
      //如果不在这里onError拦截,则在app最外层错误拦截,实测最后会执行whenComplete
      XLogUtils.printLog('---socket,done,onError报错= $error, stackTrace=$stackTrace');
      xRelease();
    }).whenComplete((){
      //实测:socket断开时结束回调
      XLogUtils.printLog('---socket,done,whenComplete');
      xRelease();
      //socket断连通知
      if(disconnectCallback!=null){
        disconnectCallback!(ip,port);
      }
    });

    if(isReceiveMsg){
      //接收消息
      _receiveMsg();
    }

  }

  @override
  void xRelease() {
    try {
      //XLogUtils.printLog('---socket?.destroy()');
      //socket?.close();//只关闭本端,不能发送数据
      socket?.destroy();//关闭双向,不在接收和发送数据,需要发送消息内部才能检测是否关闭,因此需要心跳包

      //
      _noteWaitServerSocketReceivedResponseOkMap.removeWhere(
              (key, value)
          {
            //取消
            (value['timer'] as Timer?)?.cancel();
            //
            XBaseQueueMessage? nMsg=value['msg'];
            if(nMsg!=null && !nMsg.isHeartbeatCommand){
              XSocketDeviceNotifyCallback.instance.writeMsgToSocketDeviceCallback(
                isServer:isServer,
                isSuccess:false,
                ip:ip,
                msg:nMsg,
              );
            }

            return true;
          }
      );

    }catch (error) {
      XLogUtils.printLog('xRelease,catch: $error');
    }finally{
      socket=null;
    }
  }


  //1.发送消息
  bool sendMsg(XBaseQueueMessage msg) {
    //注意:实测写入成功并不一定意味着服务器成功接收了消息，因为网络传输可能会出现各种问题。
    // 如:断开wifi,非主动关闭服务端socket情况下, 客户端socket写入返回成功,但服务端无法收到,实际已断链,无法使用trycatch拦截,无法判断
    //如果需要确保消息被服务器接收，通常需要在应用层实现确认机制，例如请求服务器返回确认消息

    try{
      if(socket!=null){

        if(isCustomSocketCommunication){
          //自定义socket通讯
          Map<String,dynamic> customSocketDataMap={
            'msgId':msg.msgId,
          };

          if(msg.isHeartbeatCommand){
            //心跳包
            customSocketDataMap['XDataType']=XConstants.XCustomSocketHeartbeatData;
          }else if(msg.isMsgReceivedCommand){
            //收到对方消息回调响应ok
            //XLogUtils.printLog('---发送收到对方socket消息确认回调');
            customSocketDataMap['XDataType']=XConstants.XCustomSocketReceiveDataSucceed;
          }else{
            customSocketDataMap['XDataType']=XConstants.XCustomSocketData;
            customSocketDataMap['XData']=msg.message;
          }
          //
          msg.message=customSocketDataMap;

          //实测write/writeln在断连发送也不会报错,因此无法使用trycatch拦截
          /*
          socket.writeln(msg);//实测会分开发送内容后,再发送\n,导致接收消息时是分开2次接收,因此该用write
          XJsonUtils.obj2Json():适配map和string
          自动添加\n结尾,适配android原生等接收规则
           */
          String str=XJsonUtils.obj2Json(msg.message);
          //字符串转base64传输,保留消息内的所有字符,同时避免接收时utf8转换错误
          socket!.write('${XJiamiUtils.strToBase64(str)}\n');
          //socket!.add(msg.message_Uint8List!);

        }else{
          
          if(msg.isHeartbeatCommand){
            //心跳包
            Map<String,dynamic> customSocketDataMap={
              'msgId':msg.msgId,
            };
            customSocketDataMap['XDataType']=XConstants.XCustomSocketHeartbeatData;
            msg.message=customSocketDataMap;
          }

          if(msg.message_Uint8List!=null){
            socket!.add(msg.message_Uint8List!);
          }else if(msg.message!=null) {
            //实测write/writeln在断连发送也不会报错,因此无法使用trycatch拦截

            /*
          socket.writeln(msg);//实测会分开发送内容后,再发送\n,导致接收消息时是分开2次接收,因此该用write
          socket.writeAll(list,'\n');//多段发送,中间添加分隔
          XJsonUtils.obj2Json():适配map和string
          自动添加\n结尾,适配android原生等接收规则
           */
            String str=XJsonUtils.obj2Json(msg.message);
            //防止中间有\n,可能业务需要,如打印
            //str=str.replaceAll('\n', '');
            //写入
            socket!.write('$str\n');
          }

        }

        //await socket.flush();//实测不要在write/writeln后使用socket.flush();会报错
        //XLogUtils.printLog('---socket!.write end');
        return true;
      }

    }catch(e){
      //socket断连,实测最后会执行.whenComplete
      XLogUtils.printLog('---socket sendMsg报错:$e');
      xRelease();
    }finally{
      //客户端(自定义socket通讯,非socket打印机)发送消息,需要服务端回调收到确认发送成功,自定义10秒超时则失败
      if(!isServer && isCustomSocketCommunication && !_noteWaitServerSocketReceivedResponseOkMap.containsKey(msg.msgId)){

        Map<String,dynamic> noteNewMap={};
        noteNewMap['msg']=msg;
        noteNewMap['timer']= Timer(const Duration(seconds: 30),(){
          //
          XLogUtils.printLog('---client socket写入超30秒没收到确认响应,失败,msg=${msg.msgId}');

          //清除记录
          xRelease();
          //socket断连通知
          if(disconnectCallback!=null){
            disconnectCallback!(ip,port);
          }

        }
        );
        _noteWaitServerSocketReceivedResponseOkMap[msg.msgId]=noteNewMap;

        if(!msg.isHeartbeatCommand && !msg.isMsgReceivedCommand){
          XLogUtils.printLog('---client自定义socket通讯,开启服务端收到确认回调,timer超时检测waitResponse=${_noteWaitServerSocketReceivedResponseOkMap.length}');
        }

      }
    }

    return false;

  }
  //记录等待服务端收到返回确认
  Map<String,dynamic> _noteWaitServerSocketReceivedResponseOkMap={};

  /*
  接收消息
  实测:内容过长,底层会自动分段传输,判断是否完整内容需要判断是否以\n作为结束,因此发送消息也需要以\n结尾
   */
  String totalMessage='';
  void _receiveMsg(){
    //注意:socket.listen()只能订阅一次,会替代旧的
    //socket?.asBroadcastStream().listen() 使用多个订阅
    socket?.listen((Uint8List data) {
      //utf8
      String msgStr='';
      try{
        msgStr=XStringUtils.uint8ListToString_utf8(data);
        //msgStr.trim()会去除\n,因此不能在这里执行
        //msgStr=msgStr.trim();
      }catch(e){
        XLogUtils.printLog('---socket.listen,uint8ListToString_utf8,err=$e');
      }

      // if(msgStr.contains('\n')){
      //   XLogUtils.printLog('---自定义socket通讯receiveMsg收到:msgStr contains /n');
      // }else{
      //   XLogUtils.printLog('---自定义socket通讯receiveMsg收到:msgStr not contains /n');
      // }
      if(totalMessage.startsWith('\n')){
        totalMessage=totalMessage.substring(1);
      }

      if(XStringUtils.isEmpty(msgStr)){
        return;
      }

      //自定义socket通讯,非socket打印机)
      if(isCustomSocketCommunication){
        //
        totalMessage='$totalMessage$msgStr';
        //实测:当子设备并发发送时,接收时会出现多段\n同时接收,则\n可能在中间位置
        if(!totalMessage.contains('\n')){
          XLogUtils.printLog('---自定义socket通讯receiveMsg收到:部分消息');
          return;
        }

        //---自定义socket通讯receiveMsg收到:完整消息
        List<String> listStr=totalMessage.split('\n');

        int size_listStr=listStr.length;
        for(int ij=0; ij<size_listStr;ij++){
          /*
          1.刚好\n结尾,最后一个元素为'',list至少有2个元素,
          2./n在中间,最后一个元素不完整,
          即无论如何,最后一个元素不处理
           */
          if(ij==size_listStr-1){
            break;
          }

          String iStr=listStr[ij];
          //替换消费掉当前
          totalMessage=totalMessage.replaceFirst(iStr, '');

          if(!XStringUtils.isEmpty(iStr)){
            //base64转字符串
            String strMsg=XJiamiUtils.base64ToString(iStr);
            //strMsg=strMsg.trim();
            //XLogUtils.printLog('---strMsg=$strMsg',isPrintAll: true);
            if(!XStringUtils.isEmpty(strMsg)){
              if(strMsg.startsWith('{') && strMsg.endsWith('}')){
                //处理每段消息
                _handle_customSocketCommunication_stringMsg_async(strMsg);
              }
            }
          }
          //
          if(totalMessage.startsWith('\n')){
            totalMessage=totalMessage.substring(1);
          }
        }

      }else{
        //
        XLogUtils.printLog('---非自定义socket通讯,receiveMsg收到消息=$msgStr');
        msgStr=msgStr.trim();
        //msgStr=msgStr.replaceAll('\n', '');
        //注意:返回对方(客户端或服务端)的地址和端口,而socket.address.address和socket.port是自己的地址和端口
        XSocketDeviceNotifyCallback.instance.receiveSocketDeviceMsgCallback(
            isServer,
            ip,//对方ip:socket.remoteAddress.address,
            port,//对方端口: socket.remotePort,
            msgStr
        );

      }



    }).onError((e){
      XLogUtils.printLog('---socket _receiveMsg onError: $e');
      //socket 断连,实测最后会执行.whenComplete
      xRelease();
    }
    );

  }


  //处理每段消息
  void _handle_customSocketCommunication_stringMsg_async(String iStr){
    Future((){

      Map<String,dynamic> receiveMap=XJsonUtils.json2Map(iStr);
      if(receiveMap['XDataType']!=XConstants.XCustomSocketReceiveDataSucceed && receiveMap['XDataType']!=XConstants.XCustomSocketHeartbeatData){
        XLogUtils.printLog('---自定义socket通讯_handleMsg_stringItem_async,msgId=${receiveMap['msgId']}');
      }

      if(isServer){
        //服务端收到消息则发送确认响应
        sendMsg(
            XBaseQueueMessage(
              msgId: receiveMap['msgId']??'服务端socket收到发送确认回调msgId为null??',
              isMsgReceivedCommand: true,
            )
        );

      }else{
        //客户端
        //XLogUtils.printLog('---客户端自定义socket通讯receiveMsg收到消息=$totalMessage');

        if(receiveMap['XDataType']==XConstants.XCustomSocketReceiveDataSucceed){
          //收到服务端确认回调
          String? msgId=receiveMap['msgId'];
          //XLogUtils.printLog('---自定义clientSocket收到服务端确认响应,msgId=$msgId');
          //清除记录,避免存在重复
          _noteWaitServerSocketReceivedResponseOkMap.removeWhere((key, value){
            if(key==msgId){
              //取消
              Timer? timer=value['timer'];
              timer?.cancel();
              //
              XBaseQueueMessage? nMsg=value['msg'];
              if(nMsg!=null && !nMsg.isHeartbeatCommand){
                //
                XLogUtils.printLog('---client socket收到服务端确认响应,msgId=${nMsg.msgId}');
                XSocketDeviceNotifyCallback.instance.writeMsgToSocketDeviceCallback(
                  isServer:isServer,
                  isSuccess:true,
                  ip:ip,
                  msg:nMsg,
                );
              }
              return true;
            }

            return false;
          });

        }
      }

      //心跳包则不通知
      if(receiveMap['XDataType']==XConstants.XCustomSocketHeartbeatData
          || receiveMap['XDataType']==XConstants.XCustomSocketReceiveDataSucceed){
        return;
      }

      //注意:返回对方(客户端或服务端)的地址和端口,而socket.address.address和socket.port是自己的地址和端口
      XSocketDeviceNotifyCallback.instance.receiveSocketDeviceMsgCallback(
          isServer,
          ip,//对方ip:socket.remoteAddress.address,
          port,//对方端口: socket.remotePort,
          iStr
      );

    });
  }



}